﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml.Serialization;
using Warensoft.Unity.Communication.Client;
namespace Warensoft.Unity.Communication.Client.DataClient
{
    [Serializable]
    class WhereFunctionClass
    {
        public string Key { get; set; }
        public object Value { get; set; }
        public bool Function(DataRow row)
        {
            return row[this.Key].Equals(this.Value);
        }
    }
    
    
    public class QueryData
    {

        public string TypeName { get; set; }

        public string Key { get; set; }
        
        public object Value { get; set; }
               
        public int Take { get; set; }
       
        public int Skip { get; set; }
       
        public string OrderBy { get; set; }
       
        public string OrderByDesc { get; set; }
       
        public Warensoft.Unity.Communication.Client.QueryType Type { get; set; }

        public QueryData()
        {
            this.Key = "";
            this.Take = -1;
            this.Skip = -1;
            //this.OrderBy = "";
            //this.OrderByDesc = "";
            this.TypeName = "System.Object";
            this.Type = QueryType.None;
        }
        public static QueryData Create(byte[] buffer)
        {
            QueryData query = new QueryData();
            using (MemoryStream ms = new MemoryStream(buffer))
            {
                using (BinaryReader br = new BinaryReader(ms))
                {
                    query.Key = br.ReadString();
                   
                    query.Take = br.ReadInt32();
                    query.Skip = br.ReadInt32();
                    //query.OrderBy = br.ReadString();
                    //query.OrderByDesc = br.ReadString();
                    query.Type = (QueryType)br.ReadByte();
                    query.TypeName = br.ReadString();
                    
                    var valueLength = br.ReadInt32();
                    if (valueLength != 0)
                    {
                        byte[] valueBuffer = new byte[valueLength];
                        br.Read(valueBuffer, 0, valueBuffer.Length);
                        BinaryFormatter bf = new BinaryFormatter();
                        MemoryStream ms1 = new MemoryStream(valueBuffer);
                        query.Value  = bf.Deserialize(ms1);
                        ms1.Close();
                    }
                   
                }
            }
            return query;
        }
        
        public byte[] ToArray()
        {

            byte[] buffer = null;
            using (MemoryStream ms = new MemoryStream())
            {
                using (BinaryWriter bw = new BinaryWriter(ms))
                {
                    bw.Write(this.Key);
                    bw.Write(this.Take);
                    bw.Write(this.Skip);
                    //bw.Write(this.OrderBy);
                    //bw.Write(this.OrderByDesc);
                    bw.Write((byte)this.Type);
                    bw.Write(this.TypeName);
                    if (this.Value == null)
                    {
                        bw.Write((int)0);
                    }
                    else
                    {
                        BinaryFormatter bf = new BinaryFormatter();
                        MemoryStream ms1 = new MemoryStream();
                        bf.Serialize(ms1, this.Value );
                        var valueBuffer = ms1.ToArray();
                        bw.Write(valueBuffer.Length);
                        bw.Write(valueBuffer,0,valueBuffer .Length );
                        ms1.Close();
                    }
                   

                }
                buffer = ms.ToArray();
            }
            return buffer;
        }

        
    }
    
    public class DataQuery
    {
        
        private List<QueryData> queries = new List<QueryData>();
        public List<QueryData> Queries
        {
            get
            {
                return this.queries;
            }
        }
        private List<DataQuery> mergedQueries = new List<DataQuery>();
        public List<DataQuery> MergedQueries
        {
            get
            {
                return this.mergedQueries;
            }
        }

        public DataQuery EqualsTo<T>(string key, T value)where T:IComparable
        {
            this.queries.Add(new QueryData() 
            {
                Type = QueryType.EqualsTo,
                Key=key,
                Value=value,
                TypeName=typeof (T).Name
            });
            return this;
        }
        public DataQuery NotEqualsTo<T>(string key, T value) where T : IComparable
        {
            this.queries.Add(new QueryData()
            {
                Type = QueryType.NotEqualsTo,
                Key = key,
                Value = value,
                TypeName = typeof(T).Name
            });
            return this;
        }
        public DataQuery GreaterThan<T>(string key, T value) where T:IComparable
        {
            this.queries.Add(new QueryData()
            {
                
                Type = QueryType.GreaterThan,
                Key = key,
                Value = value,
                TypeName = typeof(T).Name

            });
            return this;
        }
        public DataQuery GreaterThanOrEqualsTo<T>(string key, T value) where T : IComparable
        {
            this.queries.Add(new QueryData()
            {
                Type = QueryType.GreaterThanOrEqualsTo,
                Key = key,
                Value = value,
                TypeName = typeof(T).Name
            });
            return this;
        }
        public DataQuery SmallerThan<T>(string key, T value) where T:IComparable
        {
            this.queries.Add(new QueryData()
            {
                Type = QueryType.SmallerThan,
                Key = key,
                Value = value,
                TypeName = typeof(T).Name
            });
            return this;
        }
        public DataQuery SmallerThanOrEqualsTo<T>(string key, T value)where T:IComparable
        {
            this.queries.Add(new QueryData()
            {
                Type = QueryType.SmallerThanOrEqualsTo,
                Key = key,
                Value = value,
                TypeName = typeof(T).Name
            });
            return this;
        }
        public DataQuery OrderBy(string key)
        {
            this.queries.Add(new QueryData() 
            {
                Type= QueryType.OrderBy,
                Key=key
            });
            return this;
        }
        public DataQuery OrderByDescending(string key)
        {
           
            this.queries.Add(new QueryData()
            {
                
                Type = QueryType.OrderByDesc,
                 Key=key
            });
            return this;
        }
        public DataQuery Take(int count)
        {
            this.queries.Add(new QueryData() 
            {
                Type=  QueryType.Take,
                Take=count
            });
            return this;
        }
        public DataQuery Skip(int count)
        {
            this.queries.Add(new QueryData()
            {
                Type = QueryType.Skip,
                Skip=count
            });
            return this;
        }
        public static DataQuery Or(DataQuery q1,DataQuery q2)
        {
            q1.mergedQueries.Add(q2);
            return q1;
        }
        public static DataQuery And(DataQuery q1, DataQuery q2)
        {
            foreach (var query in q2.queries )
            {
                q1.queries.Add(query);
            }
            return q1;
        }
        public static DataQuery Create(byte[] buffer)
        {
            DataQuery query = new DataQuery();
            using (MemoryStream ms=new MemoryStream (buffer))
            {
                using (BinaryReader br=new BinaryReader (ms))
                {
                    int length = br.ReadInt32();
                    for (int i = 0; i < length; i++)
                    {
                        int datalength = br.ReadInt32();
                        byte[]dataBuffer=new byte[datalength];
                        br.Read(dataBuffer,0,dataBuffer .Length);
                        QueryData data = QueryData.Create(dataBuffer);
                        query.queries.Add(data);
                    }
                    var mergedQueriesLength = br.ReadInt32();

                    for (int i = 0; i < mergedQueriesLength; i++)
                    {
                        int queryLength = br.ReadInt32();
                        byte[] queryBuffer = new byte[queryLength];
                        br.Read(queryBuffer, 0, queryBuffer.Length);
                        var subQuery = DataQuery.Create(queryBuffer);
                        query.mergedQueries.Add(subQuery);
                    }
                }
            }
            return query;
        }
        public byte[] ToArray()
        {
            byte[] buffer = null;
            using (MemoryStream ms=new MemoryStream ())
            {
                using (BinaryWriter bw=new BinaryWriter (ms))
                {
                    bw.Write(this.queries .Count );
                    foreach (var query in this.queries)
                    {
                        var queryBuffer = query.ToArray();
                        bw.Write(queryBuffer .Length );
                        bw.Write(queryBuffer ,0,queryBuffer .Length );
                    }
                    bw.Write(this.MergedQueries.Count);
                    foreach (var query in this.MergedQueries)
                    {
                        var queryBuffer = query.ToArray();
                        bw.Write(queryBuffer.Length);
                        bw.Write(queryBuffer, 0, queryBuffer.Length);
                    }
                }
                buffer = ms.ToArray();
            }
            return buffer;
        }
        #region operators
        
        #endregion
    }
}
